home *** CD-ROM | disk | FTP | other *** search
- /* :bk=0 */
-
- /****************************************************************************/
- /* */
- /* Dissolve.c */
- /* */
- /* Author: Lee M. Robertson */
- /* Based on an article in the Nov '86 Doctor Dobb's Journal */
- /* by Mike Morton */
- /****************************************************************************/
-
- #include "fcntl.h"
- #include "exec/types.h"
- #include "exec/memory.h"
- #include "graphics/copper.h"
- #include "graphics/gfx.h"
- #include "graphics/view.h"
- #include "graphics/rastport.h"
- #include "hardware/blit.h"
- #include "hardware/custom.h"
- #include "intuition/intuition.h"
-
- /*---------------------------------------------------------------------------
- * following are definitions from the IFF specification
- *-------------------------------------------------------------------------*/
- struct BitMapHeader
- {
- UWORD w, h;
- WORD x, y;
- UBYTE nPlanes;
- UBYTE masking;
- UBYTE compression;
- UBYTE pad1;
- UWORD transparentColor;
- UBYTE xAspect, yAspect;
- WORD pageWidth, pageHeight;
- };
-
- typedef unsigned long ID;
-
- struct Chunk
- {
- ID ckID;
- long ckSize;
- };
-
- struct ColorRegister
- {
- UBYTE red, green, blue;
- };
-
- #define CSIZE sizeof(chunk)
- #define BMHDSIZE sizeof( struct BitMapHeader)
-
- #define mskNone 0
- #define mskHasMask 1
- #define mskHasTransparentColor 2
- #define mskLasso 3
- #define cmpNone 0 /* file is not compressed */
- #define cmpByteRun1 1 /* file is Run Length Encoded */
-
- #define MakeID(a,b,c,d) ( (long)(a)<<24 | (long)(b)<<16 | (long)(c)<<8 | (d) )
- #define FORM MakeID('F','O','R','M')
- #define ILBM MakeID('I','L','B','M')
- #define LIST MakeID('L','I','S','T')
- #define BODY MakeID('B','O','D','Y')
- #define BMHD MakeID('B','M','H','D')
- #define CMAP MakeID('C','M','A','P')
-
- /*---------------------------------------------------------------------------
- * Picture structure - this contains all the revalent data for a picture file
- *-------------------------------------------------------------------------*/
- /* define for the # of bytes in the color register map */
- #define CMSIZE 3*32
-
- struct picture
- {
- int numcolors; /* # of valid colors */
- int fd; /* the file # for this file */
- struct BitMap *bm; /* a bitmap to store the picture */
- long bodysize; /* # of bytes in the body data */
- struct BitMapHeader bmhd;
- UBYTE cmap[CMSIZE]; /* the color values for this picture */
- /* don't use the ColorRegister structure if using Aztec 'C' */
- };
-
- struct picture pic1,pic2; /* some picture sturcts */
- struct BitMap BitMap; /* bitmap to read pictue into */
- struct GfxBase *GfxBase;
- struct IntuitionBase *IntuitionBase;
- struct Window *Window;
- struct Screen *Screen;
- struct ViewPort *vp,*ViewPortAddress();
-
- void *OpenLibrary();
- void *GetMsg();
- void *AllocMem();
- void *OpenScreen();
- void *OpenWindow();
-
- #define INTUITION_REV 29L
- #define GRAPHICS_REV 29L
-
- struct NewWindow NewWindow =
- {
- 0, /* left edge */
- 0, /* top edge */
- 320, /* width */
- 200, /* heigth */
- 0,1, /* pen's */
-
- /* IDCmpFlags */
- RAWKEY | MOUSEBUTTONS | CLOSEWINDOW,
-
- /* flags */
- RMBTRAP | WINDOWCLOSE | BACKDROP | NOCAREREFRESH | BORDERLESS | ACTIVATE,
-
- 0, /* gadget list */
- 0, /* check mark */
- 0, /* title pointer */
- 0, /* screen pointer */
- 0, /* bitmap pointer */
- 0,0, /* minimum sizes */
- 0,0, /* maximum sizes */
- CUSTOMSCREEN,
- };
-
- struct NewScreen NewScreen =
- {
- 0, /* left edge */
- 0, /* top edge */
- 320, /* width */
- 200, /* heigth */
- 5, /* depth */
- 0,1, /* pen's */
- 0, /* view modes */
- CUSTOMSCREEN, /* type */
- 0, /* font */
- (UBYTE *)"Screen", /* title */
- 0, /* gagets */
- 0, /* bitmap */
- };
-
-
- /*---------------------------------------------------------------------------
- * main()
- *-------------------------------------------------------------------------*/
- main(argc,argv)
- int argc;
- char *argv[];
- {
- char *open_pic();
- char *rd_bmap();
- char *errmsg;
- int speed;
- register int i;
- register long psize; /* the plane size in bytes */
- register char *arg;
- register char *filename;
-
- if(argc < 2)
- {
- printf("Usage: Dissolve filename [ -# ]\n");
- exit(0);
- }
-
- for( i=1; i < argc; i++ )
- {
- argv++;
- arg = *argv;
- if( *arg == '-' )
- speed = atoi( arg + 1 );
- else
- filename = arg;
- }
-
- if( speed < 100 )
- speed = 1000;
-
- open_libs(); /* open the libraries */
-
- /* open the picture files */
- if( errmsg = open_pic( filename, &pic1 ))
- {
- printf("%s: %s\n",errmsg,filename );
- end( 10 );
- }
- /* setup the temp bitmap for the data */
- BitMap.BytesPerRow = (pic1.bmhd.w >> 4) << 1;
- BitMap.Rows = pic1.bmhd.h;
- BitMap.Depth = pic1.bmhd.nPlanes;
-
- psize = BitMap.BytesPerRow * BitMap.Rows; /* calculate the plane size */
-
- if( psize == 0 || pic1.bmhd.nPlanes > 6 )
- {
- printf("Ivalid parameters: %s\n",filename);
- end( 10 );
- }
-
- NewScreen.Width = pic1.bmhd.w;
- NewScreen.Height = pic1.bmhd.h;
- NewScreen.Depth = pic1.bmhd.nPlanes;
-
- /* set bits for display modes */
- if( NewScreen.Depth == 6 && NewScreen.Width <= 320 )
- NewScreen.ViewModes |= HAM;
-
- if( NewScreen.Height > 200 )
- NewScreen.ViewModes |= LACE;
-
- if( NewScreen.Width > 320 )
- NewScreen.ViewModes |= HIRES;
-
- Screen = OpenScreen( &NewScreen);
- if( Screen == 0 )
- {
- printf("Can't open Screen\n");
- end(10);
- }
-
- NewWindow.Screen = Screen;
- NewWindow.Width = pic1.bmhd.w;
- NewWindow.Height = pic1.bmhd.h;
- Window = OpenWindow( &NewWindow );
- if( Window == 0 )
- {
- printf("Can't open Window\n");
- end( 10 );
- }
- ShowTitle( Screen, 0L ); /* hide the screen title */
- vp = ViewPortAddress( Window ); /* get the windows viewport */
-
- SetRast( Window->RPort, 0L ); /* clear the screen */
- setcolors( vp, &pic1.cmap[0], pic1.numcolors );
-
- errmsg = "No memory for BitMap";
- /* Allocate memory for plane data */
- for( i=0; i<BitMap.Depth; i++ )
- {
- if( (BitMap.Planes[i] = AllocMem( psize, MEMF_CHIP)) == 0 )
- goto nomem;
- }
-
- /* Now read the picture into the temp bitmap */
- errmsg = rd_bmap( &BitMap, &pic1 );
-
- if( errmsg == 0 )
- {
- if( (dissolve( &BitMap, Window->RPort->BitMap, speed) ) == 0 )
- {
- while( get_message() == 0 )
- WaitPort( Window->UserPort);
- }
- }
-
- nomem:
- for( i=0; i<8; i++)
- {
- if( BitMap.Planes[i] )
- FreeMem( BitMap.Planes[i],psize );
- }
- if( errmsg )
- printf("%s: %s\n",errmsg,filename);
- end( 0 );
-
- }
-
- /*---------------------------------------------------------------------------
- * open_pic() -- open a picture file and initialize the picture data struct
- *-------------------------------------------------------------------------*/
- char * open_pic( filename, pic )
- char *filename; /* the picture file name */
- register struct picture *pic; /* the picture data */
- {
- register int fd; /* the picture file descriptor */
- struct Chunk chunk; /* temp for read data */
- register int cmsize;
-
- fd = open( filename, O_RDONLY); /* open the file */
- if( fd == -1)
- return "Can't open";
-
- if( read(fd, &chunk, CSIZE) != CSIZE )
- goto readerr;
-
- if( chunk.ckID != FORM)
- return "Not a picture file";
-
- /* check for ILBM file */
- if( read(fd, &chunk, sizeof(long) ) != sizeof(long) )
- goto readerr;
- if( chunk.ckID != ILBM )
- return "Not an ILBM file";
-
- if( read(fd, &chunk, CSIZE) != CSIZE )
- goto readerr;
-
- if( chunk.ckID != BMHD)
- return "bit map header expected";
-
- if( chunk.ckSize != BMHDSIZE )
- return "Incorrect BMHD size";
-
- /* read the BMHD data */
- if( read( fd, &pic->bmhd, BMHDSIZE ) != BMHDSIZE )
- goto readerr;
-
- pic->numcolors = 1; /* set default color map */
-
- /* read chunks untill body is found */
- while( read(fd, &chunk, CSIZE) == CSIZE )
- {
-
- if( chunk.ckID == CMAP)
- {
- /* read the color map */
-
- /* get size of the color map */
- if( chunk.ckSize > CMSIZE )
- cmsize = CMSIZE;
- else
- cmsize = chunk.ckSize;
-
- if( read(fd, &pic->cmap[0], cmsize ) != cmsize )
- goto readerr;
- pic->numcolors = cmsize / 3; /* save # of colors in picture */
-
- chunk.ckSize++;
- chunk.ckSize &= ~1;
-
- if( chunk.ckSize -= cmsize )
- lseek( fd, chunk.ckSize, 1 ); /* skip rest of colormap */
- }
-
- if( chunk.ckID == BODY )
- {
- pic->bodysize = chunk.ckSize;
- pic->fd = fd;
- return 0; /* no errs */
- }
-
- /* else ignore this chunks data */
- lseek(fd,chunk.ckSize,1);
- }
-
- readerr:
- return "Read error";
- }
-
- /*---------------------------------------------------------------------------
- * open_libs() -- open the required libraries
- *-------------------------------------------------------------------------*/
- open_libs()
- {
- if( !(IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV)) )
- {
- printf("Can't open Intuition library\n");
- exit(5);
- }
-
- if( !(GfxBase = OpenLibrary("graphics.library",GRAPHICS_REV)) )
- {
- printf("Can't open Graphics library\n");
- CloseLibrary(IntuitionBase);
- exit(5);
- }
- }
-
- /*---------------------------------------------------------------------------
- * end() -- cleanup and exit
- *-------------------------------------------------------------------------*/
- end( err )
- int err;
- {
- /* cleanup stuff */
- if( Window )
- CloseWindow( Window );
- if( Screen )
- CloseScreen( Screen );
- if( GfxBase )
- CloseLibrary(GfxBase);
- if( IntuitionBase )
- CloseLibrary(IntuitionBase);
-
- exit( err );
- }
-
- /*---------------------------------------------------------------------------
- * setcolors() -- set the color registers
- *-------------------------------------------------------------------------*/
- setcolors( vp, creg, numcolors )
- struct ViewPort *vp;
- register UBYTE *creg; /* the color values */
- int numcolors; /* the # of colors to set */
- {
- register ULONG r,g,b; /* the RGB color values (temporaries) */
- register int i;
-
- for(i=0; i<numcolors; i++)
- {
- r = *creg++ >> 4;
- g = *creg++ >> 4;
- b = *creg++ >> 4;
- SetRGB4( vp, (long)i, (long)r, (long)g, (long)b );
- }
- }
-
- /*---------------------------------------------------------------------------
- *
- *-------------------------------------------------------------------------*/
- get_message()
- {
- register ULONG class;
- register USHORT code;
- register struct IntuiMessage *Message;
- static int retval = 0;
-
- while( Message = GetMsg(Window->UserPort) )
- {
- class = Message->Class;
- code = Message->Code;
- ReplyMsg(Message);
-
- /* allow any key press to end program */
- if( class == CLOSEWINDOW || class == RAWKEY )
- retval = 1;
- /* allow user to hold program with right mouse button */
- else if( class == MOUSEBUTTONS && code == MENUDOWN )
- WaitPort( Window->UserPort);
- }
- return retval;
- }
-
- /*---------------------------------------------------------------------------
- * rd_bmap() -- read a picture into a bitmap
- * This routine assumes the bitmap is the correct size to recieve
- * the picture. No error checking is done.
- *-------------------------------------------------------------------------*/
- char *rd_bmap( bm, pic)
- struct BitMap *bm;
- struct picture *pic;
- {
- register UBYTE *buffer; /* the picture file data */
- register UBYTE *data;
- register unsigned int i;
- register unsigned long size;
- register int nplanes; /* # of data planes */
- UBYTE *planes[8]; /* array of pointers to plane data */
- void *lmalloc();
- char *error;
-
- if( !( buffer = lmalloc( pic->bodysize)) )
- return "No Memory for body buffer";
-
- error = 0; /* clear for return */
-
- size = pic->bodysize;
- data = buffer;
-
- /* read the picture data */
- while( size )
- {
- if( size >= 0x10000 )
- i = 0xffff;
- else
- i = size;
- if( read( pic->fd, data, i ) != i )
- {
- error = "Read error";
- goto err;
- }
- data += i;
- size -= i;
- }
-
- /* setup the data to pass to the decode routines */
-
- nplanes = pic->bmhd.nPlanes;
- if( pic->bmhd.masking == mskHasMask )
- nplanes++; /* add 1 for the mask plane */
-
- for( i=0; i < 8; i++ )
- planes[i] = bm->Planes[i]; /* copy plane pointers */
-
- i = (pic->bmhd.w >> 4) << 1; /* # of bytes per row */
-
- if( pic->bmhd.compression == cmpNone )
- decode0( planes,buffer,i,pic->bmhd.h,nplanes);
- else if( pic->bmhd.compression == cmpByteRun1 )
- decode1( planes,buffer,i,pic->bmhd.h,nplanes);
- else
- error = "Can't decode";
-
- err:
- free( buffer ); /* dealloc the file data buffer */
- return error;
- }
-
- /*---------------------------------------------------------------------------
- * decode0() -- decodes the body data with no compression
- *-------------------------------------------------------------------------*/
- decode0( planes,data,w,h,nplanes)
- UBYTE *planes[];
- register UBYTE *data;
- register int w,h,nplanes;
- {
- register UBYTE **pp; /* pointer to current plane data */
- register int pcnt; /* plane counter */
-
- for( ; h; h--) /* for each row */
- {
- for( pcnt = nplanes, pp = planes; pcnt; pcnt--, pp++ )
- {
- if( *pp ) /* don't move the data if no destination plane */
- {
- movmem( data, *pp, w);
- *pp += w;
- }
- data += w;
- }
- }
- }
-
- /*---------------------------------------------------------------------------
- * decode1() -- decodes the body data with ByteRun1 compression
- * this should really be in assembly
- *-------------------------------------------------------------------------*/
- decode1( planes,data,w,h,nplanes)
- UBYTE *planes[];
- register BYTE *data;
- int w,h,nplanes;
- {
- register UBYTE **pp; /* pointer to current plane data */
- register int pcnt; /* plane counter */
- register int len;
- register int n;
-
- for( ; h; h--) /* for each row */
- {
- for( pcnt = nplanes, pp = planes; pcnt; pcnt--, pp++ )
- {
- for(n=w; n > 0; n -= len )
- {
- len = *data++;
- if( len >= 0 )
- {
- len++;
- if( *pp ) /* move the data if destination plane */
- {
- movmem( data, *pp, len);
- *pp += len;
- }
- data += len;
- }
- else if( len != -128 ) /* ignore nop's */
- {
- len = -len;
- len++;
- if( *pp ) /* move the data if destination plane */
- {
- setmem( *pp, len, *data );
- *pp += len;
- }
- data++;
- }
- else
- len = 0; /* if nop */
- }
- }
- }
- }
-
- /*---------------------------------------------------------------------------
- * some global variables for the dissolve function
- *-------------------------------------------------------------------------*/
- unsigned long rand_mask; /* the mask value for the random # generator */
- unsigned long rand_val; /* the current random # value */
- unsigned long rand_tbl[] = /* the table of random mask values */
- { /* from Nov '86 DDJ p. 48 */
- 0,0, /* first 2 values don't work */
- 3,6,
- 0xc,0x14,
- 0x30,0x60,
- 0xb8,0x110,
- 0x240,0x500,
- 0xca0,0x1b00,
- 0x3500,0x6000,
- 0xb400,0x12000,
- 0x20400,0x72000,
- 0x90000,0x140000,
- 0x300000,0x420000,
- 0xd80000,0x1200000,
- 0x3880000,0x7200000,
- 0x9000000,0x14000000,
- 0x32800000,0x48000000,
- 0xa3000000 /* for 32 bits wide */
- };
-
- /*---------------------------------------------------------------------------
- * dissolve() -- dissolve one bitmap into another
- * this only works for full width bit maps
- *-------------------------------------------------------------------------*/
- dissolve( src, dst, speed )
- struct BitMap *src,*dst;
- int speed;
- {
- register UBYTE *mplane; /* the dissolve mask plane */
- register long psize; /* the size of a plane */
- register long nbits; /* # of bits in a plane */
- register int done;
-
- psize = src->BytesPerRow * src->Rows;
-
- if( (mplane = AllocMem( psize, MEMF_CHIP | MEMF_CLEAR) ) == 0 )
- return -1;
-
- nbits = psize << 3;
- nbits--; /* max bit is 1 less */
-
- /* initialize the random number generator */
- rand_val = 1;
- rand_mask = rand_tbl[ bitwidth(nbits) ];
- mplane[0] |= 1; /* set the first bit in the mask plane */
-
- done = 0; /* clear done flag */
- while( done == 0 )
- {
- done = setbits( mplane, nbits, speed );
- BlitBitMapMask( src, dst, mplane );
- if( get_message() )
- break;
- }
-
- FreeMem( mplane, psize );
- return 0;
- }
-
- /*---------------------------------------------------------------------------
- * setbits() -- set random bits in a plane
- *-------------------------------------------------------------------------*/
- setbits( plane, maxbit, numbits )
- UBYTE *plane;
- unsigned long maxbit;
- unsigned int numbits;
- {
- #asm
- ;register useage: d5 - max bit # to set, d4 - random generator mask
- ; d3 - current random value, d2 - byte offset in array for bit
- ; d2 - bit # to set, d1 - loop counter
- regs reg d2-d5
-
- movem.l regs,-(a7)
- move.l 8(a5),a0 ;get base address of array
- move.l 12(a5),d5 ;get maxbit number
- move 16(a5),d1 ;get # of bits to set
- move.l _rand_mask,d4
- move.l _rand_val,d3
- move.l #0,d0 ;clear ret val for not finished
- subq #1,d1
- loop
- lsr.l #1,d3 ;rand_val >>= 1;
- bhi ok ;bif not 0 || no carry
- xor
- eor.l d4,d3 ;rand_val ^= rand_mask;
- ok
- cmp.l d5,d3 ;if( rand_val > maxbit )
- bls setbit ;go set the bit if ok
- bra loop
- setloop
- lsr.l #1,d3 ;do the shift
- bls xor ;bif need to do the exculsive or
- setbit
- move.l d3,d2 ;copy to temp reg
- lsr.l #3,d2 ;make it a byte offset
- bset d3,0(a0,d2.l) ;set the bit in the array
- dbne d1,setloop ;end if bit is already set || # of bits done
- beq ret
- move.l #1,d0 ;set ret val for finished
- ret
- move.l d3,_rand_val ;save new random value
- movem.l (a7)+,regs
- #endasm
-
- }
-
- /*---------------------------------------------------------------------------
- * bitwidth() -- get the # of bits in a long number
- *-------------------------------------------------------------------------*/
- bitwidth( n )
- register unsigned long n;
- {
- register int w;
-
- w = 0;
-
- while( n )
- {
- w++;
- n >>= 1;
- }
- return w;
- }
-
- /*---------------------------------------------------------------------------
- *
- *-------------------------------------------------------------------------*/
-